package com.cgly.medical.aspect;

import com.cgly.medical.annotation.WxlRateLimiter;
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;

/**
 * @author wangxiangli
 * @create 2022-07-13-18:46
 */
@Component
@Aspect
public class RateLimiterAspect {


    @Resource
    private HttpServletResponse response;
    //创建了一个令牌桶限流算法的限流器
    private RateLimiter rateLimiter= RateLimiter.create(2);

//    @Pointcut("execution(public * com.study.controller.*.*(..))")
//    public void pointcut(){
//
//    }
    @Pointcut("execution(* com.cgly.medical.controller.*.*(..))")
    public void pointcut2(){}


    @Around("pointcut2()")
    public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++");
        //拿到所有的方法
        MethodSignature signature =(MethodSignature) proceedingJoinPoint.getSignature();
        //获取方法上的注解
        WxlRateLimiter wxlRateLimiter=signature.getMethod().getDeclaredAnnotation(WxlRateLimiter.class);
        if(wxlRateLimiter==null){
//            正常执行方法
            return proceedingJoinPoint.proceed();
        }
        //获取注解是的参数，获取配置的速率
        double rate=wxlRateLimiter.rate();
        //获取注解是的参数，获取等待令牌等待时间
        long timeout=wxlRateLimiter.timeOut();
        //设置限流速率
        rateLimiter.setRate(rate);
        //判断令牌桶获取token是否超时
        boolean tryAcquire = rateLimiter.tryAcquire(timeout, TimeUnit.MICROSECONDS);
        if(!tryAcquire){

            //服务降级
            fullback();
            return null;
        }
        //获取到令牌，直接执行
        return proceedingJoinPoint.proceed();
    }



    //服务降级的方法
    private void fullback(){
        response.setHeader("Content-type","text/html;charset=UTF-8");
        PrintWriter writer=null;
        try{
            System.out.println("服务繁忙，请稍等会");
            writer=response.getWriter();
            writer.println("哎呀，服务器开小差了，请重试一下");
            writer.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(null!=writer){
                writer.close();
            }
        }
    }
}
